/*
* Copyright (c)  2017, ueboot.com
* All rights reserved.
* 2017-10-14 21:04:14
*/
package com.ueboot.weishop.service.activity.impl;

import com.ueboot.core.repository.BaseRepository;
import com.ueboot.core.service.impl.BaseServiceImpl;
import com.ueboot.core.utils.DateUtils;
import com.ueboot.weishop.common.CacheKeys;
import com.ueboot.weishop.entity.activity.ActivityAttrEntity;
import com.ueboot.weishop.entity.activity.ActivityEntity;
import com.ueboot.weishop.entity.goods.GoodsInfoEntity;
import com.ueboot.weishop.entity.order.OrderEntity;
import com.ueboot.weishop.entity.order.OrderEnum;
import com.ueboot.weishop.repository.activity.ActivityAttrRepository;
import com.ueboot.weishop.repository.activity.ActivityRepository;
import com.ueboot.weishop.service.activity.ActivityAttrService;
import com.ueboot.weishop.service.activity.ActivityService;
import com.ueboot.weishop.service.cache.CacheService;
import com.ueboot.weishop.service.goods.GoodsInfoService;
import com.ueboot.weishop.service.order.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by Neel  on 2017-10-14 21:04:14.
 *
 * @author yangkui
 * @since 2.0 by autocode
 */
@Slf4j
@Service
public class ActivityServiceImpl extends BaseServiceImpl<ActivityEntity> implements ActivityService {
	@Autowired
	private ActivityRepository activityRepository;


	@Autowired
	private ActivityAttrService activityAttrService;


	@Autowired
	private ActivityAttrRepository activityAttrRepository;

	@Autowired
	private GoodsInfoService goodsInfoService;

	@Autowired
	private CacheService cacheService;
	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private OrderService orderService;

	@Override
	protected BaseRepository getBaseRepository() {
		return activityRepository;
	}

	/**
	 * 根据类型查询不同的活动列表
	 *
	 * @param pageable 分页数据
	 * @param type     类型，参加模型类的定义
	 * @return
	 */
	@Override
	public Page<ActivityEntity> findByTypeOrderByStartTimeAsc(Pageable pageable, String type) {
		return activityRepository.findByType(pageable, type);
	}

	/**
	 * 保存活动信息，需要同时更新商品对应的活动信息
	 *
	 * @param entity
	 */
	@Override
	@Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
	@CacheEvict(key = "'weishop:activity:'+#entity.getSn()", cacheNames = "activity")
	public void saveActivity(ActivityEntity entity, Long goodsId) {
		if (entity.getId() == null) {
			this.save(entity);
			GoodsInfoEntity goodsInfo = goodsInfoService.get(goodsId);
			Assert.isNull(goodsInfo.getActivity(), "该商品已经关联了其他的活动，无法再次关联！");
			goodsInfo.setActivity(entity);
			goodsInfo.setActivityFullPathIds(goodsInfo.getId() + "");
			goodsInfo.setActivityFullPathName(entity.getName());
			goodsInfoService.save(goodsInfo);
		} else {
			this.save(entity);
		}
	}


	/**
	 * 保存活动信息，同时更新活动属性表
	 *
	 * @param entity
	 */
	@Override
	@Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
	@CacheEvict(key = "'weishop:activity:'+#entity.getSn()", cacheNames = "activity")
	public void saveActivity(ActivityEntity entity, List<ActivityAttrEntity> attrs) {
		if (entity.getId() == null) {
			this.save(entity);
			activityAttrService.save(entity.getSn() ,attrs);
		} else {
			this.save(entity);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
	@CacheEvict(key = "'weishop:activity:'+#entity.getSn()", cacheNames = "activity")
	public void saveActivityGoods(ActivityEntity entity, Long[] goodsIds) {
		if (entity == null) {
			return;
		}
		if (goodsIds == null || goodsIds.length <= 0) {
			return;
		}

		for (Long goodsId : goodsIds) {
			GoodsInfoEntity goodsInfo = goodsInfoService.get(goodsId);
			Assert.isNull(goodsInfo.getActivity(), "该商品已经关联了其他的活动，无法再次关联！");
			goodsInfo.setActivity(entity);
			goodsInfo.setActivityFullPathIds(entity.getId() + "");
			goodsInfo.setActivityFullPathName(entity.getName());
			goodsInfoService.save(goodsInfo);
		}
	}

	/**
	 * 删除活动时，需要同时更新商品对应的活动信息
	 *
	 * @param id
	 */
	@Override
	@Transactional(rollbackFor = Exception.class, timeout = 30, propagation = Propagation.REQUIRED)
	@CacheEvict(allEntries = true,cacheNames = "activity")
	public void deleteActivity(Long id) {
		ActivityEntity entity = this.get(id);
		Assert.notNull(entity);
		List<GoodsInfoEntity> goods = goodsInfoService.findByActivityId(id);
		for (GoodsInfoEntity goodsInfo : goods) {
			goodsInfo.setActivity(null);
			goodsInfo.setActivityFullPathName(null);
			goodsInfo.setActivityFullPathIds(null);
			goodsInfoService.save(goodsInfo);
		}
		//删除活动属性
		List<ActivityAttrEntity> attrs = activityAttrRepository.findBySn(entity.getSn());
		for (ActivityAttrEntity item : attrs) {
			activityAttrService.delete(item.getId());
		}

		this.delete(id);
	}

	/**
	 * 清空缓存
	 */
	@Override
	@CacheEvict(allEntries = true,cacheNames = "activity")
	public void clearActivityCache() {
		log.info("清空活动对象数据相关的缓存");
	}

	/**
	 * 根据活动代码查询活动，默认会从缓存当中查询
	 *
	 * @param sn 活动代码
	 * @return
	 */
	@Override
	@Cacheable(key = "'weishop:activity:'+#sn", cacheNames = "activity")
	public ActivityEntity findBySn(String sn) {
		return activityRepository.findBySn(sn);
	}

	/**
	 * 根据活动ID查询活动，默认会从缓存当中查询
	 *
	 * @param id 数据库ID
	 * @return
	 */
	@Override
	@Cacheable(key = "'weishop:activity:'+#id", cacheNames = "activity")
	public ActivityEntity findById(Long id) {
		log.info("ActivityEntity 查询数据库");
		return activityRepository.findById(id);
	}

	@Override
	@CacheEvict(allEntries = true,cacheNames = "activity")
	public void updateActivityEntity(ActivityEntity act) {
		this.save(act);
	}

	/**
	 * 监听redis失效接口，进行活动的库存回滚
	 *
	 * @param redisMessage
	 */
	@Override
	public void rollbackStock(String redisMessage) {
		log.info("接收到redis失效事件message:{}", redisMessage);
		if (redisMessage.startsWith(CacheKeys.ACT_UNPAY_ORDER_LIST)) {
			log.info("回滚库存");
			String[] a = redisMessage.split(":");
			String sn = a[a.length - 2];
			String orderNo = a[a.length - 1];
			String key = "rollback:" + sn + ":" + orderNo;
			boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "rollback");
			//只有占位成功，才处理，防止多个应用同时处理
			if (flag) {
				redisTemplate.expire(key, 1, TimeUnit.HOURS);
				ActivityEntity act = activityRepository.findBySn(sn);
				OrderEntity orderEntity = orderService.findByOrderNo(orderNo);

				String rollBackKey = sn+":"+act.getId();
				if(!StringUtils.isEmpty(orderEntity.getCountKey())){
					rollBackKey +=":"+orderEntity.getCountKey();
				}
				cacheService.putRollbackOrder(rollBackKey, orderNo,orderEntity.getGoodsCount());
				//修改订单状态
				log.info("订单号:{},进行回滚后，设置状态为已过期!", orderNo);
				orderService.updateOrderStatus(orderNo, OrderEnum.ORDER_STATUS_3);
				log.info("回滚完成,本次回滚{}个库存",orderEntity.getGoodsCount());
			} else {
				log.info("回滚操作取消，已经由其他线程处理！");
			}

		}
	}

	@Override
	@Cacheable(key = "'weishop:activity:'+#activitySN+#type+#status", cacheNames = "activity")
	public ActivityEntity findTopBySnAndTypeAndStatusOrderByFirstInsertDesc(String activitySN, String type, String status) {
		return activityRepository.findTopBySnAndTypeAndStatusOrderByFirstInsertDesc(activitySN, type, status);
	}


	/**
	 * 查询当天的代金券活动
	 * @param type
	 * @param date
	 * @return
	 */
	@Override
	@Cacheable(key = "'weishop:activity:' + #type + ':' + #date", cacheNames = "activity")
	public List<ActivityEntity> findByTypeAndDate(String type, String date) {
		Date startTime = DateUtils.parseDate(date, DateUtils.FORMAT_DATE_YYYY_MM_DD);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startTime);
		calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + 1);

		Date endTime = calendar.getTime();

		return activityRepository.findByTypeAndStatusAndStartTimeBetweenAndEndTimeBetween(type, ActivityEntity.STATUS_OPENING, startTime, endTime, startTime, endTime);
	}



	@Override
	@Cacheable(key = "'weishop:activity:1220:crowdFund'", cacheNames = "activity")
	public List<ActivityEntity> findByTypeOrderByStartTimeAsc(String type) {
		return activityRepository.findByTypeAndStatusOrderByStartTimeAsc(type, ActivityEntity.STATUS_OPENING);
	}
}
